package com.demo.base.json;

import com.demo.base.utils.ListUtils;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * Created by ethan on 2017/8/4.
 */
public class JSONArray extends ArrayList<Object> implements Serializable {

    private static final ObjectMapper OBJECT_MAPPER = JSON.createObjectMapper();

    public JSONArray() {
        super();
    }

    public JSONArray(List<Object> list) {
        super(list);
    }

    public JSONArray(int initialCapacity) {
        super(initialCapacity);
    }

    public String toJSONString() {
        return JSON.toJSONString(this);
    }

    public Object[] toArray() {
        return this.toArray();
    }

    public <T> T[] toArray(T[] a) {
        return this.toArray(a);
    }

    public <T> List<T> toTypedList(Class<T> clazz) {
        return ListUtils.map(this, it -> {
            if (it == null) return null;
            return JSON.createObjectMapper().convertValue(it, clazz);
        });
    }

    public <T> List<T> toJavaList(Class<T> clazz) {
        return ListUtils.map(this, it -> {
            if (it == null) return null;
            return JSON.createObjectMapper().convertValue(it, clazz);
        });
    }

    public JSONArray fluentAdd(Object e) {
        add(e);
        return this;
    }

    public JSONArray fluentAddAll(Collection<? extends Object> collection) {
        addAll(collection);
        return this;
    }

    @SuppressWarnings("Duplicates")
    public JSONObject getJSONObject(int index) {
        Object value = get(index);
        if (value == null) return null;

        if (value instanceof JSONObject) {
            return (JSONObject) value;
        }

        if (value instanceof String) {
            return JSON.parseObject((String) value, JSONObject.class);
        }
        return OBJECT_MAPPER.convertValue(value, JSONObject.class);
    }

    public JSONArray getJSONArray(int index) {
        Object value = get(index);
        if (value == null) return null;

        if (value instanceof JSONArray) {
            return (JSONArray) value;
        }

        if (value instanceof String) {
            return JSON.parseObject((String) value, JSONArray.class);
        }

        throw new RuntimeException("the item is not json array or json array string");
    }

    public <T> T getJavaObject(int index, Class<T> clazz) {
        Object value = get(index);
        if (value == null) return null;

        return OBJECT_MAPPER.convertValue(value, clazz);
    }

    public <T> T getJavaObject(int index, TypeReference<T> typeReference) {
        Object value = get(index);
        if (value == null) return null;

        return OBJECT_MAPPER.convertValue(value, typeReference);
    }

    public Boolean getBoolean(int index) {
        return getJavaObject(index, Boolean.class);
    }

    public Byte getByte(int index) {
        return getJavaObject(index, Byte.class);
    }

    public byte[] getBytes(int index) {
        return getJavaObject(index, byte[].class);
    }

    public Short getShort(int index) {
        return getJavaObject(index, Short.class);
    }

    public Integer getInteger(int index) {
        return getJavaObject(index, Integer.class);
    }

    public Long getLong(int index) {
        return getJavaObject(index, Long.class);
    }

    public Float getFloat(int index) {
        return getJavaObject(index, Float.class);
    }

    public Double getDouble(int index) {
        return getJavaObject(index, Double.class);
    }

    public BigDecimal getBigDecimal(int index) {
        return getJavaObject(index, BigDecimal.class);
    }

    public BigInteger getBigInteger(int index) {
        return getJavaObject(index, BigInteger.class);
    }

    public String getString(int index) {
        return getJavaObject(index, String.class);
    }

    public Date getDate(int index) {
        return getJavaObject(index, Date.class);
    }

    public LocalTime getLocalTime(int index) {
        return getJavaObject(index, LocalTime.class);
    }

    public LocalDate getLocalDate(int index) {
        return getJavaObject(index, LocalDate.class);
    }

    public LocalDateTime getLocalDateTime(int index) {
        return getJavaObject(index, LocalDateTime.class);
    }
}
